﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;

namespace AutoCooker8
{
    public delegate void CookStartedReply();
    public delegate void CookProgressingReply();
    public delegate int CookCompletedReply();

    /// <summary>    
    /// </summary>
    class AutoCooker8
    {
        // enent关键字在委托的外边包装了一个 property，仅让 C#客户通过 += 和 -=操作符来添加和移除，不能直接激发事件。
        public event CookStartedReply started;
        public event CookProgressingReply progressing;
        public event CookCompletedReply completed;

        public void DoCook()
        {
            Console.WriteLine("AutoCooker start to cook");
            if (started != null) started();

            Console.WriteLine("AutoCooker is cooking");
            if (progressing != null) progressing();

            Console.WriteLine("AutoCooker finish to Cook");
            if (completed != null)
            {
                // 更加苛刻的情况是这样的，Mother和Son有自己的事情要做，也就是说，委托调用的时间比较长，
                // 假设Son的CookCompleted动作，sleep 3秒，Mother的CookCompleted动作Sleep8秒；DoWork()的CookCompleted动作Sleep1秒。            
                System.Threading.Thread.Sleep(1000);                

                // 为了受到每个反馈，
                // 深入到代理里面，轮询监听者列表，手工一个个调用：
                foreach (CookCompletedReply item in completed.GetInvocationList())
                {
                    // 异步委托调用，主线程和委托调用分别进行
                    // AutoCooker通知了Son和Mother已经Complete后，可以立即返回工作，例如在DoWork()后调用AutoCooker的其他方法。

                    // 改进，真正的异步委托轮询， 
                    // 既能异步委托调用，又做到轮询调用结果
                    item.BeginInvoke(new AsyncCallback(GetAppetite), item);             
                    
                }
            }
        }

        /// <summary>
        /// The signature for the call back method must be same System.IAsyncResult delegate.
        /// </summary>
        /// <param name="res"></param>
        private void GetAppetite(IAsyncResult res)
        {
            #region snppet
            // 这样也可以reterive delegate
            // AsyncResult result = (AsyncResult)res;
            // CookCompletedReply ccR = (CookCompletedReply)result.AsyncDelegate;
            // 这是第四个参数
            // object c = res.AsyncState;
            #endregion

            // 如果BeginInvoke传递的最后一个参数是调用时的委托，则res.AsyncState就可以得到这个委托
            CookCompletedReply ccR = (CookCompletedReply)res.AsyncState;
            int grade = ccR.EndInvoke(res);
            Console.WriteLine("My appetite is {0} %", grade);
        }
    }
}
